using JT808Protocol.Common;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace JT808Protocol.Models
{
    /// <summary>
    /// JT808部标数据包结构
    /// </summary>
    public class JT808Package
    {
        /// <summary>
        /// 起始标识位
        /// </summary>
        public const byte BeginFlag = 0x7E;

        /// <summary>
        /// 消息头
        /// </summary>
        [JsonPropertyName("消息头")] public JT808Header Header { get; set; }

        /// <summary>
        /// 消息体
        /// </summary>
        [JsonPropertyName("消息体")] public IJT808Body Body { get; set; }

        /// <summary>
        /// 校验码
        /// </summary>
        [JsonPropertyName("校验码")] public byte CheckCode { get; set; }

        /// <summary>
        /// 终止标识位
        /// </summary>
        public const byte EndFlag = 0x7E;

        /// <summary>
        /// 错误信息
        /// </summary>
        [JsonPropertyName("错误信息")] public string ErrMsg { get; set; }

        /// <summary>
        /// 原始数据
        /// </summary>
        [JsonIgnore] public byte[] OrginalData { get; private set; }

        /// <summary>
        /// 无参构造
        /// </summary>
        public JT808Package()
        {
            Header = new JT808Header();
        }

        /// <summary>
        /// 消息包构造
        /// </summary>
        /// <param name="MsgId">消息类型</param>
        /// <param name="Body">消息体</param>
        /// <param name="SimNumber">终端号</param>
        /// <param name="SerialNumber">流水号</param>
        /// <param name="Version">协议版本号，默认为2019</param>
        public JT808Package(ushort MsgId, string SimNumber, ushort SerialNumber, IJT808Body Body = null, JT808ProtocolVersion Version = JT808ProtocolVersion.v2019)
        {
            //初始化头部
            var bodyLen = (ushort)(Body == null ? 0 : Body.WriteToBytes().Count);
            Header = new JT808Header(MsgId, SimNumber, SerialNumber, bodyLen, Version);
            this.Body = Body;
        }

        /// <summary>
        /// 消息包构造
        /// </summary>
        /// <param name="MsgId">消息类型</param>
        /// <param name="Body">消息体</param>
        /// <param name="SimNumber">终端号</param>
        /// <param name="SerialNumber">流水号</param>
        /// <param name="Version">协议版本号，默认为2019</param>
        public JT808Package(EnumMessageType MsgType, string SimNumber, ushort SerialNumber, IJT808Body Body = null, JT808ProtocolVersion Version = JT808ProtocolVersion.v2019)
            : this((ushort)MsgType, SimNumber, SerialNumber, Body, Version)
        {
        }

        /// <summary>
        /// 消息包解析
        /// </summary>
        /// <param name="data"></param>
        public void ReadEntity(ReadOnlySpan<byte> data)
        {
            OrginalData = data.ToArray();

            int startIndex = 1;

            Header = new JT808Header();
            Header.ReadHeader(data, ref startIndex);

            //获取消息体解析策略
            Body = JT808MsgBodyParserFactory.GetBodyParser(Header.MessageType);

            try
            {
                if (Body != null)
                {
                    Body.SetHeaderContext(Header);
                    Body.ReadBody(data, ref startIndex);
                }
                else
                    ErrMsg = $"类型[{Header.MessageID}]的消息体解析器未实现";
            }
            catch (Exception ex)
            {
                ErrMsg = ex.Message;
            }

            CheckCode = data[data.Length - 2];
        }

        /// <summary>
        /// 写入数据包到Span
        /// </summary>
        /// <param name="isEsc">是否转义</param>
        /// <returns></returns>
        public ReadOnlySpan<byte> WriteSpan(bool isEsc)
        {
            List<byte> buffer = WriteEntity(isEsc);
            return new ReadOnlySpan<byte>(buffer.ToArray());
        }

        /// <summary>
        /// 写入数据包到Memory
        /// </summary>
        /// <param name="isEsc">是否转义</param>
        /// <returns></returns>
        public ReadOnlyMemory<byte> WriteMemory(bool isEsc)
        {
            List<byte> buffer = WriteEntity(isEsc);
            return new ReadOnlyMemory<byte>(buffer.ToArray());
        }

        /// <summary>
        /// 写入数据包到byte[]
        /// </summary>
        /// <param name="isEsc">是否转义</param>
        /// <returns></returns>
        public byte[] WriteBuffer(bool isEsc)
        {
            List<byte> buffer = WriteEntity(isEsc);
            return buffer.ToArray();
        }

        private List<byte> WriteEntity(bool isEsc)
        {
            List<byte> retBytes = new List<byte>();
            retBytes.Add(0x7E);//标识头

            List<byte> bodyBytes = null;
            try
            {
                if (Body != null)
                {
                    bodyBytes = Body.WriteToBytes(); //数据体转字节
                                                     //消息体数据写入数组方法可能未实现,通常是8001用的比较多
                    Header.MessageBodyProperties.BodyLength = bodyBytes.Count;//赋数据体长度
                }
            }
            catch
            {
            }

            var header = Header.WriteToBytes(); //数据头转字节

            if (isEsc)
            {
                var content = new List<byte>();
                content.AddRange(header);
                if (bodyBytes != null)
                    content.AddRange(bodyBytes);
                byte checkCode = ParseHelper.CheckSum(content.ToArray(), 0, content.Count - 1);
                content.Add(checkCode);//校验码

                retBytes.AddRange(ParseHelper.Esc(content.ToArray(), 0, content.Count - 1)); //转义
            }
            else
            {
                retBytes.AddRange(header);
                if (bodyBytes != null)
                    retBytes.AddRange(bodyBytes);
                byte checkCode = ParseHelper.CheckSum(retBytes.ToArray(), 1, retBytes.Count - 1);
                retBytes.Add(checkCode);//校验码
            }

            retBytes.Add(0x7E);//标识尾
            return retBytes;
        }
    }
}